//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2003 Intrinsyc Europe Ltd.
//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2004 Siemens AG
//
// Version: 1.1.2.5
// Date:    11. Jan. 2006
//////////////////////////////////////////////////////////////////////////////
//
//
// (C) Copyright 2007 Marvell International Ltd.
//  All Rights Reserved
//


#include "precomp.h"

BOOL g_fGPRSActive = FALSE;
#ifdef RIL_FAKECSQ
extern volatile BOOL g_fFakeSignalStrength;
#endif

// Note: Remember all LISTSTRINGMAP/LISTVALUEMAP structures must be sorted by the string/value key (not the flags key).
// This is because the range parse functions use bsearch to search for the flags fields.

static const LISTSTRINGMAP g_GprsPDPTypes[] =
{
    {"IP",    RIL_GPRSPROTOCOL_IP    },
    {"OSPIH", RIL_GPRSPROTOCOL_IHOSP },
    {"PPP",   RIL_GPRSPROTOCOL_PPP   },
    {"X25",   RIL_GPRSPROTOCOL_X25   },
};
#define NUM_GPRSPDPTYPES     (sizeof(g_GprsPDPTypes) / sizeof(LISTSTRINGMAP))

static const LISTSTRINGMAP g_GprsL2Protocols[] =
{
    {"NULL",  RIL_GPRSL2PROTOCOL_NULL },
    {"PAD",   RIL_GPRSL2PROTOCOL_PAD  },
    {"PPP",   RIL_GPRSL2PROTOCOL_PPP  },
    {"X25",   RIL_GPRSL2PROTOCOL_X25  },
};
#define NUM_GPRSL2PROTOCOLS (sizeof(g_GprsL2Protocols) / sizeof(LISTSTRINGMAP))

static const LISTVALUEMAP g_GprsDataComp[] =
{
    {0, RIL_GPRSDATACOMP_OFF},
    {1, RIL_GPRSDATACOMP_ON}
};
#define NUM_GPRSDATACOMP (sizeof(g_GprsDataComp) / sizeof(LISTVALUEMAP))

static const LISTVALUEMAP g_GprsHeaderComp[] =
{
    {0, RIL_GPRSHEADERCOMP_OFF},
    {1, RIL_GPRSHEADERCOMP_ON}
};
#define NUM_GPRSHEADERCOMP (sizeof(g_GprsHeaderComp) / sizeof(LISTVALUEMAP))

static const LISTVALUEMAP g_GprsPrecedenceClass[] =
{
    {0, RIL_GPRSPRECEDENCECLASS_SUBSCRIBED },
    {1, RIL_GPRSPRECEDENCECLASS_HIGH       },
    {2, RIL_GPRSPRECEDENCECLASS_NORMAL     },
    {3, RIL_GPRSPRECEDENCECLASS_LOW        }
};
#define NUM_GPRSPRECEDENCECLASS (sizeof(g_GprsPrecedenceClass) / sizeof(LISTVALUEMAP))

static const LISTVALUEMAP g_GprsDelayClass[] =
{
    {0, RIL_GPRSDELAYCLASS_SUBSCRIBED  },
    {1, RIL_GPRSDELAYCLASS_PREDICTIVE1 },
    {2, RIL_GPRSDELAYCLASS_PREDICTIVE2 },
    {3, RIL_GPRSDELAYCLASS_PREDICTIVE3 },
    {4, RIL_GPRSDELAYCLASS_BESTEFFORT  }
};
#define NUM_GPRSDELAYCLASS (sizeof(g_GprsDelayClass) / sizeof(LISTVALUEMAP))

static const LISTVALUEMAP g_GprsReliabilityClass[] =
{
    {0, RIL_GPRSRELIABILITYCLASS_SUBSCRIBED },
    {1, RIL_GPRSRELIABILITYCLASS_1          },
    {2, RIL_GPRSRELIABILITYCLASS_2          },
    {3, RIL_GPRSRELIABILITYCLASS_3          },
    {4, RIL_GPRSRELIABILITYCLASS_4          },
    {5, RIL_GPRSRELIABILITYCLASS_5          }
};
#define NUM_GPRSRELIABILITYCLASS (sizeof(g_GprsReliabilityClass) / sizeof(LISTVALUEMAP))

static const LISTSTRINGMAP g_GprsClass[] =
{
    {"A",    RIL_GPRSCLASS_GSMANDGPRS            },
    {"B",    RIL_GPRSCLASS_GSMORGPRS             },
    {"C",    RIL_GPRSCLASS_GSMORGPRS_EXCLUSIVE   },
    {"CC",   RIL_GPRSCLASS_GSMONLY               },
    {"CG",   RIL_GPRSCLASS_GPRSONLY              },
};
#define NUM_GPRSCLASS (sizeof(g_GprsClass) / sizeof(LISTSTRINGMAP))

static const LISTVALUEMAP g_GprsPeakThruClass[] =
{
    {0, RIL_PEAKTHRUCLASS_SUBSCRIBED },
    {1, RIL_PEAKTHRUCLASS_8000       },
    {2, RIL_PEAKTHRUCLASS_16000      },
    {3, RIL_PEAKTHRUCLASS_32000      },
    {4, RIL_PEAKTHRUCLASS_64000      },
    {5, RIL_PEAKTHRUCLASS_128000     },
    {6, RIL_PEAKTHRUCLASS_256000     },
    {7, RIL_PEAKTHRUCLASS_512000     },
    {8, RIL_PEAKTHRUCLASS_1024000    },
    {9, RIL_PEAKTHRUCLASS_2048000    }
};
#define NUM_GPRSPEAKTHRUCLASS (sizeof(g_GprsPeakThruClass) / sizeof(LISTVALUEMAP))

static const LISTVALUEMAP g_GprsMeanThruClass[] =
{
    {0,  RIL_MEANTHRUCLASS_SUBSCRIBED },
    {1,  RIL_MEANTHRUCLASS_100        },
    {2,  RIL_MEANTHRUCLASS_200        },
    {3,  RIL_MEANTHRUCLASS_500        },
    {4,  RIL_MEANTHRUCLASS_1000       },
    {5,  RIL_MEANTHRUCLASS_2000       },
    {6,  RIL_MEANTHRUCLASS_5000       },
    {7,  RIL_MEANTHRUCLASS_10000      },
    {8,  RIL_MEANTHRUCLASS_20000      },
    {9,  RIL_MEANTHRUCLASS_50000      },
    {10, RIL_MEANTHRUCLASS_100000     },
    {11, RIL_MEANTHRUCLASS_200000     },
    {12, RIL_MEANTHRUCLASS_500000     },
    {13, RIL_MEANTHRUCLASS_1000000    },
    {14, RIL_MEANTHRUCLASS_2000000    },
    {15, RIL_MEANTHRUCLASS_5000000    },
    {16, RIL_MEANTHRUCLASS_10000000   },
    {17, RIL_MEANTHRUCLASS_20000000   },
    {18, RIL_MEANTHRUCLASS_50000000   },
    {31, RIL_MEANTHRUCLASS_DONTCARE   }
};
#define NUM_GPRSMEANTHRUCLASS (sizeof(g_GprsMeanThruClass) / sizeof(LISTVALUEMAP))

static const LISTVALUEMAP g_GprsMOSMSService[] =
{
    {0,  RIL_MOSMSSERVICE_GPRS              },
    {1,  RIL_MOSMSSERVICE_CIRCUIT           },
    {2,  RIL_MOSMSSERVICE_GPRSPREFERRED     },
    {3,  RIL_MOSMSSERVICE_CIRCUITPREFERRED  }
};
#define NUM_GPRSMOSMSSERVICE (sizeof(g_GprsMOSMSService) / sizeof(LISTVALUEMAP))


#define MAX_CONTEXTS    2

BYTE g_RILGPRSContext[MAX_CONTEXTS*(sizeof(RILGPRSCONTEXT))];
RILGPRSQOSPROFILE g_RILGPRSQoSMin[MAX_CONTEXTS];
RILGPRSQOSPROFILE g_RILGPRSQoSReq[MAX_CONTEXTS];

#define INVALID_CGACT_VALUE 0xFF
UINT g_RILCGACT[MAX_CONTEXTS];

void ClearGPRSParamCache()
{
    int i;

    memset(g_RILGPRSContext, 0, MAX_CONTEXTS*(sizeof(RILGPRSCONTEXT)));
    memset(g_RILGPRSQoSMin, 0, MAX_CONTEXTS*(sizeof(RILGPRSQOSPROFILE)));
    memset(g_RILGPRSQoSReq, 0, MAX_CONTEXTS*(sizeof(RILGPRSQOSPROFILE)));
    for (i = 0; i < MAX_CONTEXTS; i++)
        g_RILCGACT[i] = INVALID_CGACT_VALUE;
}

HRESULT ParseGetGPRSContextList(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetGPRSContextList);

    UINT iNrContexts, i, iWalk;
    HRESULT hr = E_FAIL;
    PBYTE pBuffer = NULL;

    pBlob = NULL;
    cbBlob = 0;

    iNrContexts = 0;
    for (i = 0; i < MAX_CONTEXTS; i++)
    {
        RILGPRSCONTEXT *pContext;

        pContext = (RILGPRSCONTEXT *)(g_RILGPRSContext + (sizeof(RILGPRSCONTEXT) * i));
        if (pContext->cbSize > 0)
            iNrContexts++;
    }

    pBuffer = (PBYTE)ReallocBlob(pBuffer, sizeof(RILGPRSCONTEXT) * iNrContexts);

    if (pBuffer == NULL)
    {
        goto Error;
    }

    iWalk = 0;
    for (i = 0; i < MAX_CONTEXTS; i++)
    {
        RILGPRSCONTEXT *pContext;

        pContext = (RILGPRSCONTEXT *)(g_RILGPRSContext + (sizeof(RILGPRSCONTEXT) * i));
        if (pContext->cbSize > 0)
        {
            memcpy(pBuffer+(sizeof(RILGPRSCONTEXT) * iWalk), pContext, sizeof(RILGPRSCONTEXT));
            iWalk++;
        }
    }

    pBlob = (void*)pBuffer;
    cbBlob = sizeof(RILGPRSCONTEXT) * iNrContexts;
    hr = S_OK;

    Error:
    if (FAILED(hr))
    {
        FreeBlob(pBuffer);
    }
    return hr;
}

// +CGDCONT?
HRESULT RILDrv_GetGPRSContextList (DWORD dwParam)
{
    TBD_FUNCTION(RILDrv_GetGPRSContextList);

    HRESULT hr = E_INVALIDARG;
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    if (!pHandle)
    {
        goto Error;
    }

    if (!QueueCmd(COMMAND_PORT, pHandle, NULL, CMDOPT_NOOP, APIID_GETGPRSCONTEXTLIST, ParseGetGPRSContextList, NULL, hr))
    {
        hr = E_FAIL;
        goto Error;
    }

    Error:
    return hr;
}

HRESULT RILDrv_SetGPRSContext (DWORD dwParam, const RILGPRSCONTEXT* lpGprsContext)
{
    TBD_FUNCTION(RILDrv_SetGPRSContext);

    HRESULT hr = E_INVALIDARG;
    char szCmd[MAX_ATCMD_LEN];
    LPSTR szWalk = szCmd;
    UINT Value;
    COM_PORT_TYPE iPort;

    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    if (!pHandle)
    {
        goto Error;
    }

    iPort = g_ComManager.GetPortFromContextId(lpGprsContext->dwContextID);

    if (iPort == INVALID_PORT)
    {
        goto Error;
    }

    // Build command
    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CGDCONT=%u,", lpGprsContext->dwContextID);
    szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
    TBD_ASSERT(NULL != szWalk);

    if (lpGprsContext->dwParams & RIL_PARAM_GCONT_PROTOCOLTYPE)
    {
        LPSTR szString;
        if (!StringFromFlag(lpGprsContext->dwProtocolType,g_GprsPDPTypes, NUM_GPRSPDPTYPES, szString))
        {
            goto Error;
        }
        (void)_snprintfz(szWalk, MAX_ATCMD_LEN - (szWalk - szCmd), "\"%s\"",szString);
        szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
        TBD_ASSERT(NULL != szWalk);
    }

    // Add ","
    (void)strncpyz(szWalk, ",", MAX_ATCMD_LEN - (szWalk - szCmd));
    szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
    TBD_ASSERT(NULL != szWalk);

    if (lpGprsContext->dwParams & RIL_PARAM_GCONT_ACCESSPOINTNAME)
    {
        (void)_snprintfz(szWalk, MAX_ATCMD_LEN - (szWalk - szCmd), "\"%s\"", AnsiString(lpGprsContext->wszAccessPointName));
        szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
        TBD_ASSERT(NULL != szWalk);
    }

    // Add ","
    (void)strncpyz(szWalk, ",", MAX_ATCMD_LEN - (szWalk - szCmd));
    szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
    TBD_ASSERT(NULL != szWalk);

    if (lpGprsContext->dwParams & RIL_PARAM_GCONT_ADDRESS)
    {
        (void)_snprintfz(szWalk, MAX_ATCMD_LEN - (szWalk - szCmd), "\"%s\"", AnsiString(lpGprsContext->wszAddress));
        szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
        TBD_ASSERT(NULL != szWalk);
    }

    // The MC75 doesn't accept any additional parameters.
    if (!IS_ADI) {
        // Add ","
        (void)strncpyz(szWalk, ",", MAX_ATCMD_LEN - (szWalk - szCmd));
        szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
        TBD_ASSERT(NULL != szWalk);

        if (lpGprsContext->dwParams & RIL_PARAM_GCONT_DATACOMPRESSION)
        {
            if (!ValueFromFlag(lpGprsContext->dwDataCompression,g_GprsDataComp,NUM_GPRSDATACOMP,Value))
            {
                goto Error;
            }
            (void)_snprintfz(szWalk, MAX_ATCMD_LEN - (szWalk - szCmd), "%u",Value);

            szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
            TBD_ASSERT(NULL != szWalk);
        }

        // Add ","
        (void)strncpyz(szWalk, ",", MAX_ATCMD_LEN - (szWalk - szCmd));
        szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
        TBD_ASSERT(NULL != szWalk);

        if (lpGprsContext->dwParams & RIL_PARAM_GCONT_HEADERCOMPRESSION)
        {
            if (!ValueFromFlag(lpGprsContext->dwHeaderCompression,g_GprsHeaderComp,NUM_GPRSHEADERCOMP,Value))
            {
                goto Error;
            }
            (void)_snprintfz(szWalk, MAX_ATCMD_LEN - (szWalk - szCmd), "%u",Value);

            szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
            TBD_ASSERT(NULL != szWalk);
        }
        else
        {
            Value = 0;
            (void)_snprintfz(szWalk, MAX_ATCMD_LEN - (szWalk - szCmd), "%u",Value);

            szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
            TBD_ASSERT(NULL != szWalk);
        }

        if (lpGprsContext->dwParams & RIL_PARAM_GCONT_PARAMETERS)
        {
            (void)_snprintfz(szWalk, MAX_ATCMD_LEN - (szWalk - szCmd), ",%s", lpGprsContext->szParameters);
            szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
            TBD_ASSERT(NULL != szWalk);
        }
    }

    // Add "\r"
    (void)strncpyz(szWalk, "\r", MAX_ATCMD_LEN - (szWalk - szCmd));

    if (!QueueCmd(iPort,
                  pHandle,
                  szCmd,
                  CMDOPT_NONE,
                  APIID_SETGPRSCONTEXT,
                  NULL,     // Parse fn
                  NULL,     // Ptr to notification data
                  hr))
    {
        hr = E_FAIL;
        goto Error;
    }

    if (lpGprsContext->dwContextID <= MAX_CONTEXTS)
    {
        RILGPRSCONTEXT *pContext;

        memcpy(g_RILGPRSContext + ((lpGprsContext->dwContextID - 1) * sizeof(RILGPRSCONTEXT)), lpGprsContext, sizeof(RILGPRSCONTEXT));
        pContext = (RILGPRSCONTEXT *)(g_RILGPRSContext + ((lpGprsContext->dwContextID - 1) * sizeof(RILGPRSCONTEXT)));
        pContext->cbSize = sizeof(RILGPRSCONTEXT);
        pContext->dwParameterLength = 0;
        pContext->dwParams &= ~RIL_PARAM_GCONT_PARAMETERS;
        memset(&g_RILGPRSQoSMin[lpGprsContext->dwContextID - 1], 0, sizeof(RILGPRSQOSPROFILE));
        memset(&g_RILGPRSQoSReq[lpGprsContext->dwContextID - 1], 0, sizeof(RILGPRSQOSPROFILE));
    }

    Error:
    return hr;
}

// +CGDCONT=<dwContextID>
HRESULT RILDrv_DeleteGPRSContext (DWORD dwParam, DWORD dwContextID)
{
    TBD_FUNCTION(RILDrv_DeleteGPRSContext);

    HRESULT hr = E_INVALIDARG;
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    if (!pHandle)
    {
        goto Error;
    }

    // Build command
    char szCmd[MAX_ATCMD_LEN];
    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CGDCONT=%u\r", dwContextID);
    if (!QueueCmd(COMMAND_PORT,
                  pHandle,
                  szCmd,
                  CMDOPT_NONE,
                  APIID_DELETEGPRSCONTEXT,
                  NULL,     // Parse fn
                  NULL,     // Ptr to notification data
                  hr))
    {
        hr = E_FAIL;
        goto Error;
    }

    if (dwContextID <= MAX_CONTEXTS)
    {
        RILGPRSCONTEXT *pContext;

        pContext = (RILGPRSCONTEXT *)(g_RILGPRSContext + ((dwContextID - 1) * sizeof(RILGPRSCONTEXT)));
        pContext->cbSize = 0;
    }
    Error:
    return hr;
}

#ifdef SIEMENS_MAGNETO
HRESULT RILDrv_NdisSetGPRSContextActivated (DWORD dwParam, const RILNDISSETGPRSCONTEXTACTIVATED *lpNdisSetGprsContextActivated )
{
    HRESULT hr = E_INVALIDARG;

    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    if (!pHandle)
    {
        goto Error;
    }

    // hr = pHandle->NdisSetGPRSContextActivated(lpNdisSetGprsContextActivated);
    hr = E_NOTIMPL;

    Error:
    return hr;
}

HRESULT RILDrv_NdisReceivePacketDone (DWORD dwParam,  RILNDISPACKET* lpNdisPacket)
{
    HRESULT hr = E_INVALIDARG;

    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    if (!pHandle)
    {
        hr = E_FAIL;
        goto Error;
    }

    // hr = pHandle->NdisReceivePacketDone(lpNdisPacket);
    hr = E_NOTIMPL;

    Error:
    return hr;
}

HRESULT RILDrv_NdisSendPacket (DWORD dwParam,  RILNDISPACKET* lpNdisPacket)
{
    HRESULT hr = E_INVALIDARG;

    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    if (!pHandle)
    {
        hr = E_FAIL;
        goto Error;
    }

    // hr = pHandle->NdisSendPacket(lpNdisPacket);
    hr = E_NOTIMPL;

    Error:
    return hr;
}
#endif // SIEMENS_MAGNETO

HRESULT ParseGetRequestedQualityOfServiceList(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetRequestedQualityOfServiceList);
    PBYTE pBuffer=NULL;
    UINT i, iNumContext, iIdx;
    HRESULT hr = E_FAIL;

    pBlob = NULL;
    cbBlob = 0;

    iNumContext = 0;
    for (i = 0; i < MAX_CONTEXTS; i++)
        if (g_RILGPRSQoSReq[i].dwContextID == i + 1)
            iNumContext++;

    pBuffer = (PBYTE)ReallocBlob(pBuffer, iNumContext * sizeof(RILGPRSQOSPROFILE));
    if (!pBuffer)
    {
        goto Error;
    }

    iIdx = 0;
    for (i = 0; i < MAX_CONTEXTS; i++)
    {
        if (g_RILGPRSQoSReq[i].dwContextID == i + 1)
        {
            memcpy(pBuffer + (iIdx * sizeof(RILGPRSQOSPROFILE)), &g_RILGPRSQoSReq[i], sizeof(RILGPRSQOSPROFILE));
            iIdx++;
        }
    }

    pBlob = (void*)pBuffer;
    cbBlob = iNumContext * sizeof(RILGPRSQOSPROFILE);
    hr = S_OK;

    Error:
    if (FAILED(hr))
    {
        FreeBlob(pBuffer);
    }
    return hr;
}

HRESULT ParseGetMinimumQualityOfServiceList(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetMinimumQualityOfServiceList);
    PBYTE pBuffer=NULL;
    UINT i, iNumContext, iIdx;
    HRESULT hr = E_FAIL;

    pBlob = NULL;
    cbBlob = 0;

    iNumContext = 0;
    for (i = 0; i < MAX_CONTEXTS; i++)
        if (g_RILGPRSQoSMin[i].dwContextID == i + 1)
            iNumContext++;

    pBuffer = (PBYTE)ReallocBlob(pBuffer, iNumContext * sizeof(RILGPRSQOSPROFILE));
    if (!pBuffer)
    {
        goto Error;
    }

    iIdx = 0;
    for (i = 0; i < MAX_CONTEXTS; i++)
    {
        if (g_RILGPRSQoSMin[i].dwContextID == i + 1)
        {
            memcpy(pBuffer + (iIdx * sizeof(RILGPRSQOSPROFILE)), &g_RILGPRSQoSMin[i], sizeof(RILGPRSQOSPROFILE));
            iIdx++;
        }
    }

    pBlob = (void*)pBuffer;
    cbBlob = iNumContext * sizeof(RILGPRSQOSPROFILE);
    hr = S_OK;

    Error:
    if (FAILED(hr))
    {
        FreeBlob(pBuffer);
    }
    return hr;
}

//
//
//
HRESULT RILDrv_GetRequestedQualityOfServiceList (DWORD dwParam)
{
    TBD_FUNCTION(RILDrv_GetRequestedQualityOfServiceList);

    HRESULT hr = E_INVALIDARG;
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    if (!pHandle)
    {
        goto Error;
    }

    if (!QueueCmd(COMMAND_PORT, pHandle, NULL, CMDOPT_NOOP, APIID_GETREQUESTEDQUALITYOFSERVICELIST, ParseGetRequestedQualityOfServiceList, NULL, hr))
    {
        hr = E_FAIL;
        goto Error;
    }

    Error:
    return hr;
}

//
//
//
HRESULT RILDrv_GetMinimumQualityOfServiceList (DWORD dwParam)
{
    TBD_FUNCTION(RILDrv_GetMinimumQualityOfServiceList);

    HRESULT hr = E_INVALIDARG;
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    if (!pHandle)
    {
        goto Error;
    }

    if (!QueueCmd(COMMAND_PORT, pHandle, NULL, CMDOPT_NOOP, APIID_GETMINIMUMQUALITYOFSERVICELIST, ParseGetMinimumQualityOfServiceList, NULL, hr))
    {
        hr = E_FAIL;
        goto Error;
    }

    Error:
    return hr;
}

// +CGQREQ=[<cid> [,<precedence > [,<delay> [,<reliability.> [,<peak> [,<mean>]]]]]]
// +CGQMIN=[<cid> [,<precedence > [,<delay> [,<reliability.> [,<peak> [,<mean>]]]]]]
/*
typedef struct rilgprsqosprofile_tag {
    DWORD cbSize;                       // @field structure size in bytes
    DWORD dwParams;                     // @field indicates valid parameters
    DWORD dwContextID;                  // @field the context number
    DWORD dwPrecedenceClass;            // @field a RIL_GPRSPRECEDENCECLASS_* constant
    DWORD dwDelayClass;                 // @field a RIL_GPRSDELAYCLASS_* constant
    WCHAR dwReliabilityClass;           // @field a RIL_GPRSRELIABILITYCLASS_* constant
    DWORD dwPeakThruClass;              // @field a RIL_GPRSPEAKTHRUCLASS_* constant
    DWORD dwMeanThruClass;              // @field a RIL_GPRSMEANTHRUCLASS_* constant
} RILGPRSQOSPROFILE, *LPRILGPRSQOSPROFILE;
*/
HRESULT SetQOS(DWORD dwParam, const RILGPRSQOSPROFILE* lpGprsQosProfile, LPCSTR szATCmd, const APIID apiid)
{
    TBD_FUNCTION(RILDrv_SetRequestedQualityOfService);

    HRESULT hr = E_INVALIDARG;
    char szCmd[MAX_ATCMD_LEN];
    LPSTR szWalk = szCmd;
    UINT Value;
    COM_PORT_TYPE iPort;
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);

    iPort = g_ComManager.GetPortFromContextId(lpGprsQosProfile->dwContextID);

    if (!pHandle || iPort == INVALID_PORT)
    {
        goto Error;
    }

    // Build command
    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT%s=%u,", szATCmd, lpGprsQosProfile->dwContextID);
    szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
    TBD_ASSERT(NULL != szWalk);

    if (lpGprsQosProfile->dwParams & RIL_PARAM_GQOSP_PRECEDENCECLASS)
    {
        if (!ValueFromFlag(lpGprsQosProfile->dwPrecedenceClass,g_GprsPrecedenceClass,NUM_GPRSPRECEDENCECLASS,Value))
        {
            goto Error;
        }
        (void)_snprintfz(szWalk, MAX_ATCMD_LEN - (szWalk - szCmd), "%u",Value);

        szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
        TBD_ASSERT(NULL != szWalk);
    }
    else
    {
        (void)_snprintfz(szWalk, MAX_ATCMD_LEN - (szWalk - szCmd), "%u", 0);

        szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
    }

    // Add ","
    (void)strncpyz(szWalk, ",", MAX_ATCMD_LEN - (szWalk - szCmd));
    szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
    TBD_ASSERT(NULL != szWalk);

    if (lpGprsQosProfile->dwParams & RIL_PARAM_GQOSP_DELAYCLASS)
    {
        if (!ValueFromFlag(lpGprsQosProfile->dwDelayClass,g_GprsDelayClass,NUM_GPRSDELAYCLASS,Value))
        {
            goto Error;
        }
        (void)_snprintfz(szWalk, MAX_ATCMD_LEN - (szWalk - szCmd), "%u",Value);

        szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
        TBD_ASSERT(NULL != szWalk);
    }
    else
    {
        (void)_snprintfz(szWalk, MAX_ATCMD_LEN - (szWalk - szCmd), "%u", 0);

        szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
    }

    // Add ","
    (void)strncpyz(szWalk, ",", MAX_ATCMD_LEN - (szWalk - szCmd));
    szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
    TBD_ASSERT(NULL != szWalk);


    if (lpGprsQosProfile->dwParams & RIL_PARAM_GQOSP_RELIABILITYCLASS)
    {
        if (!ValueFromFlag(lpGprsQosProfile->dwReliabilityClass,g_GprsReliabilityClass,NUM_GPRSRELIABILITYCLASS,Value))
        {
            goto Error;
        }
        (void)_snprintfz(szWalk, MAX_ATCMD_LEN - (szWalk - szCmd), "%u",Value);

        szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
        TBD_ASSERT(NULL != szWalk);
    }
    else
    {
        (void)_snprintfz(szWalk, MAX_ATCMD_LEN - (szWalk - szCmd), "%u", 0);

        szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
    }

    // Add ","
    (void)strncpyz(szWalk, ",", MAX_ATCMD_LEN - (szWalk - szCmd));
    szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
    TBD_ASSERT(NULL != szWalk);

    if (lpGprsQosProfile->dwParams & RIL_PARAM_GQOSP_PEAKTHRUCLASS)
    {
        if (!ValueFromFlag(lpGprsQosProfile->dwPeakThruClass,g_GprsPeakThruClass,NUM_GPRSPEAKTHRUCLASS,Value))
        {
            goto Error;
        }
        (void)_snprintfz(szWalk, MAX_ATCMD_LEN - (szWalk - szCmd), "%u",Value);

        szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
        TBD_ASSERT(NULL != szWalk);
    }
    else
    {
        (void)_snprintfz(szWalk, MAX_ATCMD_LEN - (szWalk - szCmd), "%u", 0);

        szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
    }

    // Add ","
    (void)strncpyz(szWalk, ",", MAX_ATCMD_LEN - (szWalk - szCmd));
    szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
    TBD_ASSERT(NULL != szWalk);

    if (lpGprsQosProfile->dwParams & RIL_PARAM_GQOSP_MEANTHRUCLASS)
    {
        if (!ValueFromFlag(lpGprsQosProfile->dwMeanThruClass,g_GprsMeanThruClass,NUM_GPRSMEANTHRUCLASS,Value))
        {
            goto Error;
        }
        (void)_snprintfz(szWalk, MAX_ATCMD_LEN - (szWalk - szCmd), "%u",Value);

        szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
        TBD_ASSERT(NULL != szWalk);
    }
    else
    {
        (void)_snprintfz(szWalk, MAX_ATCMD_LEN - (szWalk - szCmd), "%u", 0);

        szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
    }

    // Add "\r"
    (void)strncpyz(szWalk, "\r", MAX_ATCMD_LEN - (szWalk - szCmd));

    if (!QueueCmd(iPort,
                  pHandle,
                  szCmd,
                  CMDOPT_NONE,
                  apiid,
                  NULL,     // Parse fn
                  NULL,     // Ptr to notification data
                  hr))
    {
        hr = E_FAIL;
        goto Error;
    }

    if (apiid == APIID_SETMINIMUMQUALITYOFSERVICE && lpGprsQosProfile->dwContextID < MAX_CONTEXTS)
        memcpy(&g_RILGPRSQoSMin[lpGprsQosProfile->dwContextID - 1], lpGprsQosProfile, sizeof(RILGPRSQOSPROFILE));
    if (apiid == APIID_SETREQUESTEDQUALITYOFSERVICE && lpGprsQosProfile->dwContextID < MAX_CONTEXTS)
        memcpy(&g_RILGPRSQoSReq[lpGprsQosProfile->dwContextID - 1], lpGprsQosProfile, sizeof(RILGPRSQOSPROFILE));

    Error:
    return hr;
}

// +CGQREQ=<params>
HRESULT RILDrv_SetRequestedQualityOfService (DWORD dwParam, const RILGPRSQOSPROFILE* lpGprsQosProfile)
{
    TBD_FUNCTION(RILDrv_SetRequestedQualityOfService);
    return SetQOS(dwParam,lpGprsQosProfile, "+CGQREQ",APIID_SETREQUESTEDQUALITYOFSERVICE);
}

// +CGQMIN=<params>
HRESULT RILDrv_SetMinimumQualityOfService (DWORD dwParam, const RILGPRSQOSPROFILE* lpGprsQosProfile)
{
    TBD_FUNCTION(RILDrv_SetRequestedQualityOfService);
    return SetQOS(dwParam,lpGprsQosProfile, "+CGQMIN",APIID_SETMINIMUMQUALITYOFSERVICE);
}

HRESULT DeleteQOS(DWORD dwParam, DWORD dwContextID, LPCSTR szATCmd, const APIID apiid)
{
    TBD_FUNCTION(DeleteQOS);

    HRESULT hr = E_INVALIDARG;
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    COM_PORT_TYPE        iPort;

    iPort = g_ComManager.GetPortFromContextId(dwContextID);

    if (!pHandle || iPort == INVALID_PORT)
    {
        goto Error;
    }

    // Build command
    char szCmd[MAX_ATCMD_LEN];
    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT%s=%u\r", szATCmd, dwContextID);
    if (!QueueCmd(iPort,
                  pHandle,
                  szCmd,
                  CMDOPT_NONE,
                  apiid,
                  NULL,  // Parse fn
                  NULL,     // Ptr to notification data
                  hr))
    {
        hr = E_FAIL;
        goto Error;
    }

    if (apiid == APIID_DELETEMINIMUMQUALITYOFSERVICE && dwContextID < MAX_CONTEXTS)
        memset(&g_RILGPRSQoSMin[dwContextID - 1], 0, sizeof(RILGPRSQOSPROFILE));
    if (apiid == APIID_DELETEREQUESTEDQUALITYOFSERVICE && dwContextID < MAX_CONTEXTS)
        memset(&g_RILGPRSQoSReq[dwContextID - 1], 0, sizeof(RILGPRSQOSPROFILE));

    Error:
    return hr;
}

// +CGQREQ=<dwContextID>
HRESULT RILDrv_DeleteRequestedQualityOfService (DWORD dwParam, DWORD dwContextID)
{
    TBD_FUNCTION(RILDrv_DeleteRequestedQualityOfService);
    return DeleteQOS(dwParam, dwContextID, "+CGQREQ", APIID_DELETEREQUESTEDQUALITYOFSERVICE);
}

// +CGQMIN=<dwContextID)
HRESULT RILDrv_DeleteMinimumQualityOfService (DWORD dwParam, DWORD dwContextID)
{
    TBD_FUNCTION(RILDrv_DeleteMinimumQualityOfService);
    return DeleteQOS(dwParam, dwContextID, "+CGQMIN", APIID_DELETEMINIMUMQUALITYOFSERVICE);
}

// +CGATT=[0|1]
HRESULT RILDrv_SetGPRSAttached (DWORD dwParam, BOOL fAttached)
{
    TBD_FUNCTION(RILDrv_SetGPRSAttached);

    HRESULT hr = E_INVALIDARG;
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    if (!pHandle)
    {
        goto Error;
    }

    // Build command
    char szCmd[MAX_ATCMD_LEN];
    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CGATT=%u\r", fAttached ? 1 : 0);

    if (!QueueCmd(DATA_PORT,
                  pHandle,
                  szCmd,
                  CMDOPT_NONE,
                  APIID_SETGPRSATTACHED,
                  NULL,  // Parse fn
                  NULL,     // Ptr to notification data
                  hr))
    {
        hr = E_FAIL;
        goto Error;
    }

    Error:
    return hr;
}

/*
+CGATT: <state>
<state>: indicates the state of GPRS attachment
0 - detached
1 - attached
*/
HRESULT ParseGetGPRSAttached(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetGPRSAttached);

    UINT nValue;
    HRESULT hr = E_FAIL;
    BOOL *pbResult=NULL;

    pBlob = NULL;
    cbBlob = 0;

    // Parse "<prefix>"
    if (!ParseRspPrefix(szRsp, szRsp))
    {
        goto Error;
    }

    // Parse "+CGATT: "
    if (!MatchStringBeginning(szRsp, "+CGATT: ", szRsp))
    {
        goto Error;
    }

    // Parse <state>
    if (!ParseUInt(szRsp, TRUE, nValue, szRsp))
    {
        goto Error;
    }

    pbResult = (BOOL*)AllocBlob(sizeof(BOOL));
    if (!pbResult)
    {
        goto Error;
    }
    *pbResult=nValue;
    pBlob = (void*)pbResult;
    cbBlob = sizeof(BOOL);
    hr = S_OK;

    Error:
    if (FAILED(hr))
    {
        FreeBlob(pbResult);
    }

    return hr;
}

// +CGATT?
HRESULT RILDrv_GetGPRSAttached (DWORD dwParam)
{
    TBD_FUNCTION(RILDrv_GetGPRSAttached);

    HRESULT hr = E_INVALIDARG;
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    if (!pHandle)
    {
        goto Error;
    }

    if (!QueueCmd(COMMAND_PORT,
                  pHandle,
                  "AT+CGATT?\r",
                  CMDOPT_NONE,
                  APIID_GETGPRSATTACHED,
                  ParseGetGPRSAttached,  // Parse fn
                  NULL,     // Ptr to notification data
                  hr))
    {
        hr=E_FAIL;
        goto Error;
    }

    Error:
    return hr;
}

// +CGACT=[0|1],<dwContextID>[,<dwContextID>...]
HRESULT RILDrv_SetGPRSContextActivated (DWORD dwParam, DWORD dwContextID, BOOL fContextActivation)
{
    TBD_FUNCTION(RILDrv_SetGPRSContextActivated);

    HRESULT              hr = E_INVALIDARG;
    CRilInstanceHandle*  pHandle = ExtractHandle(dwParam);
    CComHandle*          pDataPort;
    COM_PORT_TYPE        iPort;

    iPort = g_ComManager.GetPortFromContextId(dwContextID);

    pDataPort = pHandle->GetDevice()->GetComDevice(iPort);

    if (!pHandle || !pDataPort || iPort == INVALID_PORT)
    {
        goto Error;
    }

    if(!pHandle->GetDevice()->GetDataAllowed())
    {
        RILRetailTrace((TEXT("RilDrv: Error - data connections not allowed while initializing\r\n")));
        goto Error;
    }

    RILRetailTrace((TEXT("RILDrv_GetGPRSContextActivatedList: dwContextID = %d\n"), dwContextID));        
    RILRetailTrace((TEXT("RILDrv_GetGPRSContextActivatedList: fContextActivation = %d\n"), fContextActivation));        
	
    if(!fContextActivation)
    {
        BOOL bAnyContextActive;
        INT i;

        if (dwContextID > 0 && dwContextID <= MAX_CONTEXTS)
            g_RILCGACT[dwContextID-1] = 0;

        bAnyContextActive = FALSE;
        for (i = 0; i < MAX_CONTEXTS; i++)
        {
            if (g_RILCGACT[i] == 1)
                bAnyContextActive = TRUE;
        }

        g_fGPRSActive = bAnyContextActive;
    }
    else
    {
        g_fGPRSActive = TRUE;
        if (dwContextID > 0 && dwContextID <= MAX_CONTEXTS)
			g_RILCGACT[dwContextID-1] = 1;    //Activated
//            g_RILCGACT[dwContextID-1] = 0;
    }

    RILRetailTrace((TEXT("RILDrv_GetGPRSContextActivatedList: g_fGPRSActive = %d\n"), g_fGPRSActive));        
	
    for (int i = 0; i < MAX_CONTEXTS; i++)
    {	
   	    RILRetailTrace((TEXT("RILDrv_GetGPRSContextActivatedList: g_RILCGACT[%d] = %d\n"), i, g_RILCGACT[i]));           	
	}

    // Build command
    char szCmd[MAX_ATCMD_LEN];

    if(fContextActivation)
    {
        (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CGACT=1,%u\r", dwContextID);
    }
    else
    {
        // Read the status
        if (!QueueInternalCmd(iPort, pHandle->GetDevice(), "AT+CGACT?\r", CMDOPT_NONE, APIID_SETGPRSCONTEXTACTIVATED, 0, 0, 0))
	    {
            TBD_OUTPUT(TBDCT_INFO, TBDOL_ERROR, (TEXT("RILDrv_SetGPRSContextActivated : Unable to construct or Init CCommand")));
	        hr=E_FAIL;
	        goto Error;
	    }
        // Deactivate the context
        (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CGACT=0,%u\r", dwContextID);
    }

    if (!fContextActivation)
      QueueInternalCmd(iPort, pHandle->GetDevice(), szCmd, CMDOPT_NONE, APIID_SETGPRSCONTEXTACTIVATED, 0, 2, 2000);

    /* If there is no active context, it can exit data mode now if the modem is in data mode */
    if ((!g_fGPRSActive) && (pDataPort->FDataMode()))
	{
		if (!pDataPort->TerminateDataMode())
    	{
			RILRetailTrace((TEXT("RilDrv: RILDrv_SetGPRSContextActivated Failed in TerminateDataMode() \r\n")));
    	}
			
    	RILRetailTrace((TEXT("RilDrv: RILDrv_SetGPRSContextActivated TerminateDataMode() Completed\r\n")));
	}

    if (!QueueCmd(COMMAND_PORT,
                 pHandle,
                  NULL,
                  CMDOPT_NOOP,
                 APIID_SETGPRSCONTEXTACTIVATED,
                 NULL,  // Parse fn
                 NULL,     // Ptr to notification data
                  hr))
    {
        hr=E_FAIL;
        goto Error;
    }

    Error:
    return hr;
}

/*
+CGACT: <cid>, <state>
[<CR><LF>+CGACT: <cid>, <state>
[...]]
*/
HRESULT ParseGetGPRSContextActivatedListInternal(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetGPRSContextActivatedListInternal);
    PBYTE pBuffer=NULL;
    DWORD dwBufferSize=0;
    BOOL fGPRSActivated = FALSE;
    RILGPRSCONTEXTACTIVATED *pCtxtAct;
    UINT nValue;
    HRESULT hr = E_FAIL;
    BOOL bSuccess;

    pBlob = NULL;
    cbBlob = 0;

    // Parse "<prefix>"
    if (!ParseRspPrefix(szRsp, szRsp))
    {
        goto Error;
    }

    // Parse "+CGACT: "
    while (MatchStringBeginning(szRsp, "+CGACT: ", szRsp))
    {
        // Reallocate our buffer for the additional data
        pBuffer = (PBYTE)ReallocBlob(pBuffer,dwBufferSize+sizeof(RILGPRSCONTEXTACTIVATED));
        if (!pBuffer)
        {
            goto Error;
        }

        pCtxtAct = (RILGPRSCONTEXTACTIVATED *)(pBuffer+dwBufferSize);
        memset(pCtxtAct, 0x00, sizeof(RILGPRSCONTEXTACTIVATED));
        pCtxtAct->cbSize=sizeof(RILGPRSCONTEXTACTIVATED);

        dwBufferSize+=sizeof(RILGPRSCONTEXTACTIVATED);

        // Parse <cid>
        if (!ParseUInt(szRsp, TRUE, nValue, szRsp))
        {
            goto Continue;
        }

        pCtxtAct->dwContextID=nValue;
		RILRetailTrace((TEXT("RilDrv: ParseGetGPRSContextActivatedListInternal dwContextID = %d.\r\n"), nValue));

        // Parse ,<fActivated>
        if (!ParseRspParamSeparator(szRsp, szRsp) ||
            (!ParseUInt(szRsp, TRUE, nValue, szRsp)) )
        {
            goto Continue;
        }

        // Original: pCtxtAct->fActivated = nValue; but we ignore this value and use the value given by pParam
        pCtxtAct->fActivated  = nValue;
		RILRetailTrace((TEXT("RilDrv: ParseGetGPRSContextActivatedListInternal fActivated = %d.\r\n"), nValue));
		
		//if (((pCtxtAct->dwContextID - 1) < MAX_CONTEXTS) && (pCtxtAct->dwContextID - 1 >= 0))
		//	g_RILCGACT[pCtxtAct->dwContextID - 1] = pCtxtAct->fActivated;
		RILRetailTrace((TEXT("RilDrv: ParseGetGPRSContextActivatedListInternal pParam = %d.\r\n"), (UINT)pParam));
		
        if ((UINT)pParam < MAX_CONTEXTS)
              g_RILCGACT[(UINT)pParam] = pCtxtAct->fActivated;

        // If any contexts are activated signal this
        if(pCtxtAct->fActivated)
       	{
            fGPRSActivated = TRUE;
			g_fGPRSActive = TRUE;
       	}

        Continue:
        // Find "<postfix>"
        bSuccess = FindRspPostfix(szRsp, szRsp);
        if (!bSuccess)
        {
            goto Error;
        }
    }

    pBlob = (void*)pBuffer;
    cbBlob = dwBufferSize;
    hr = S_OK;

    Error:
    if (FAILED(hr))
    {
        FreeBlob(pBuffer);
    }
    return hr;
}

HRESULT ParseGetGPRSContextActivatedList(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetGPRSContextActivatedList);
    PBYTE pBuffer=NULL;
    DWORD dwBufferSize=0;
    BOOL fGPRSActivated = FALSE;
    RILGPRSCONTEXTACTIVATED *pCtxtAct;
    HRESULT hr = E_FAIL;
    UINT i, iNumContext;

    pBlob = NULL;
    cbBlob = 0;

    iNumContext = 0;
    for (i = 0; i < MAX_CONTEXTS; i++) {
        if (g_RILCGACT[i] != INVALID_CGACT_VALUE)
            iNumContext++;
    }

    if (iNumContext > 0) {
        UINT iNum;

        pBuffer = (PBYTE)ReallocBlob(pBuffer, iNumContext*sizeof(RILGPRSCONTEXTACTIVATED));
        if (!pBuffer)
        {
            goto Error;
        }
		
		dwBufferSize = iNumContext*sizeof(RILGPRSCONTEXTACTIVATED);

        iNum = 0;
        for (i = 0; i < MAX_CONTEXTS; i++) {
            if (g_RILCGACT[i] != INVALID_CGACT_VALUE) {
                pCtxtAct = (RILGPRSCONTEXTACTIVATED *)(pBuffer+(iNum*sizeof(RILGPRSCONTEXTACTIVATED)));
                iNum += 1;
                memset(pCtxtAct, 0x00, sizeof(RILGPRSCONTEXTACTIVATED));
                pCtxtAct->cbSize = sizeof(RILGPRSCONTEXTACTIVATED);
                  
                pCtxtAct->dwContextID = (i + 1);

                pCtxtAct->fActivated = g_RILCGACT[i];

                // If any contexts are activated signal this
                if(pCtxtAct->fActivated)
                    fGPRSActivated = TRUE;
            }
        }
    }

    pBlob = (void*)pBuffer;
    cbBlob = dwBufferSize;

	
    hr = S_OK;

    Error:
    if (FAILED(hr))
    {
        FreeBlob(pBuffer);
    }
    return hr;
}

// +CGACT?
HRESULT RILDrv_GetGPRSContextActivatedList (DWORD dwParam)
{
    TBD_FUNCTION(RILDrv_GetGPRSContextActivatedList);

    HRESULT hr = E_INVALIDARG;
    COM_PORT_TYPE iPort = INVALID_PORT;
    int i = 0;
    CCommand *pTmpCmd = NULL;
    void *pBlob = NULL;
    UINT cbBlob = 0;

    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    if (!pHandle)
    {
        goto Error;
    }

    for (i = 0; i < MAX_CONTEXTS; i++)
    {
        iPort = g_ComManager.GetPortFromContextId(i+1);
        if (iPort != INVALID_PORT && g_RILCGACT[i] == INVALID_CGACT_VALUE)
        {
            if (pHandle->GetDevice()->GetComDevice(iPort)->FDataMode())
            {
                RILRetailTrace((TEXT("RILDrv_GetGPRSContextActivatedList: In Data Mode\n")));        
                RILGPRSCONTEXT *pContext;

                // If the port is in data mode it can be CSD or GPRS, so we query, if a GPRS
                // context is defined for this port. If it is, we propably have an actice
                // GPRS context, otherwise there is most likely a CSD connection going on.
                pContext = (RILGPRSCONTEXT *)(g_RILGPRSContext + (sizeof(RILGPRSCONTEXT) * i));
                if (pContext->cbSize > 0)
                    g_RILCGACT[i] = 1;
                else
                    g_RILCGACT[i] = 0;
            }
            else
            {
                RILRetailTrace((TEXT("RILDrv_GetGPRSContextActivatedList: In Command Mode\n")));        
                QueueInternalCmdBlocking(iPort, pHandle->GetDevice(), "AT+CGACT?\r", CMDOPT_NONE, APIID_GETGPRSCONTEXTACTIVATEDLIST, 0, 0, 0, ParseGetGPRSContextActivatedListInternal, NULL, (LPVOID)i);
            }
        }
    }

    if (!QueueCmd(COMMAND_PORT,
                  pHandle,
                  NULL,
                  CMDOPT_NOOP,
                  APIID_GETGPRSCONTEXTACTIVATEDLIST,
                  ParseGetGPRSContextActivatedList,  // Parse fn
                  NULL,     // Ptr to notification data
                  hr))
    {
        hr = E_FAIL;
        goto Error;
    }

    Error:

	if (pTmpCmd)
	{
		delete pTmpCmd;
        pTmpCmd = NULL;
	}

	if (pBlob)
	{
		FreeBlob(pBlob);
        pBlob = NULL;
	}

    return hr;
}

HRESULT ParseForceFailureResponse(LPCSTR, void*&, UINT&)
{
    // Force a failure
    return E_FAIL;
}

extern DWORD g_dwEnableGPRSAttach;

// +CGDATA=<params>
HRESULT RILDrv_EnterGPRSDataMode (DWORD dwParam, const RILENTERGPRSDATAMODE * lpEnterGprsDataMode)
{
    TBD_FUNCTION(RILDrv_EnterGPRSDataMode);

    HRESULT hr = E_INVALIDARG;
    char szCmd[MAX_ATCMD_LEN];
    LPSTR szWalk = szCmd;
    DWORD dwOptions = CMDOPT_NONE;
    PFN_CMD_PARSE pfnParse = NULL;
    CComHandle *pPort;
    COM_PORT_TYPE iPort;
    INT iContext = 0;

	
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    if (!pHandle)
    {
        goto Error;
    }


    if (lpEnterGprsDataMode) {
        if (lpEnterGprsDataMode->dwNumContexts != 1)
        {
            RILRetailTrace((TEXT("RilDrv: Tried to open %u contexts at the same time.\r\n"), lpEnterGprsDataMode->dwNumContexts));
            hr = E_INVALIDARG;
            goto Error;
        }
        iContext = lpEnterGprsDataMode->dwContextID[0];
    }
    else {
        iContext = 1;
    }
    iPort = g_ComManager.GetPortFromContextId(iContext);

    if (iContext > MAX_CONTEXTS) {
        hr = E_INVALIDARG;
        goto Error;
    }
    if (iPort == INVALID_PORT) {
        goto Error;
    }

     RILRetailTrace((TEXT("RilDrv: RILDrv_EnterGPRSDataMode: lpEnterGprsDataMode->cbSize = %d.\r\n"), lpEnterGprsDataMode->cbSize));
     RILRetailTrace((TEXT("RilDrv: RILDrv_EnterGPRSDataMode: lpEnterGprsDataMode->dwNumContexts = %d.\r\n"), lpEnterGprsDataMode->dwNumContexts));
     RILRetailTrace((TEXT("RilDrv: RILDrv_EnterGPRSDataMode: lpEnterGprsDataMode->dwL2Protocol  = %d.\r\n"), lpEnterGprsDataMode->dwL2Protocol));
     RILRetailTrace((TEXT("RilDrv: RILDrv_EnterGPRSDataMode: lpEnterGprsDataMode->dwContextID[0]  = %d.\r\n"), lpEnterGprsDataMode->dwContextID[0]));
     RILRetailTrace((TEXT("RilDrv: RILDrv_EnterGPRSDataMode: iPort = %d.\r\n"), iPort));
     RILRetailTrace((TEXT("RilDrv: RILDrv_EnterGPRSDataMode: iContext = %d.\r\n"), iContext));

    if(g_dwEnableGPRSAttach == 1)  {
#if defined (GPRSDIAL_REQUIRES_REGISTRATION) || defined (GPRSDIAL_REQUIRES_GPRSREGISTRATION)
        if(((g_dwRegStatus != RIL_REGSTAT_HOME) && (g_dwRegStatus != RIL_REGSTAT_ROAMING))
#if defined (GPRSDIAL_REQUIRES_GPRSREGISTRATION)
             || ((g_dwGPRSRegStatus != RIL_REGSTAT_HOME) && (g_dwGPRSRegStatus != RIL_REGSTAT_ROAMING))
#endif // #if defined (GPRSDIAL_REQUIRES_GPRSREGISTRATION)
             )
         {
            DWORD dwTimeout = 0;

            QueueInternalCmd(DATA_PORT, pHandle->GetDevice(), "AT+CGATT=1\r", CMDOPT_NONE, APIID_SETINITIALGPRSATTACHED, GPRS_WAIT_FOR_ATTACH*100, 0, 0);

            // Its not enough to wait for the OK of AT+CGATT, we also have to wait for the +CGREG-URC. So the
            // easiest way is this simple loop:
            while (g_dwGPRSRegStatus != RIL_REGSTAT_HOME && g_dwGPRSRegStatus != RIL_REGSTAT_ROAMING && dwTimeout<GPRS_WAIT_FOR_ATTACH)
            {
                Sleep(100);
                dwTimeout++;
            }
            if (g_dwGPRSRegStatus != RIL_REGSTAT_HOME && g_dwGPRSRegStatus != RIL_REGSTAT_ROAMING)
            {
                hr = E_FAIL;
                goto Error;
            }
            //dwOptions = CMDOPT_NOOP;
            //pfnParse = ParseForceFailureResponse;
        }
#endif // #if defined (GPRSDIAL_REQUIRES_REGISTRATION) || defined (GPRSDIAL_REQUIRES_GPRSREGISTRATION)
    }

    /* Query context activation */
    //if (!QueueInternalCmdBlocking(iPort, pHandle->GetDevice(), "AT+CGACT?\r", CMDOPT_NONE, APIID_GETGPRSCONTEXTACTIVATEDLIST, 0, 0, 0, ParseGetGPRSContextActivatedListInternal, NULL, (LPVOID)(iContext-1)))
	//{
		//RILRetailTrace((TEXT("RILDrv_EnterGPRSDataMode: Failed in QueueInternalCmdBlocking\n")));        
	//}
	
    //for (UINT i = 0; i < MAX_CONTEXTS; i++)
    //{	
   	//    RILRetailTrace((TEXT("RILDrv_EnterGPRSDataMode: Before g_RILCGACT[%d]= %d\n"), i, g_RILCGACT[i]));        
   	//}

    //if (!QueueInternalCmdBlocking(iPort, pHandle->GetDevice(), "AT+CGACT?\r", CMDOPT_NONE, APIID_GETGPRSCONTEXTACTIVATEDLIST, 0, 0, 0, ParseGetGPRSContextActivatedListInternal, NULL, (LPVOID)(iContext-1)))
	//{
	//	RILRetailTrace((TEXT("RILDrv_EnterGPRSDataMode: Failed in QueueInternalCmdBlocking\n")));        
	//}

    //if (g_RILCGACT[iContext-1] == 1) {
    //    char szCmdDeact[25];

    //    (void)_snprintfz(szCmdDeact, 25, "AT+CGACT=0,%d\r",  iContext);
    //    QueueInternalCmd(iPort, pHandle->GetDevice(), szCmdDeact, CMDOPT_NONE, APIID_GETGPRSCONTEXTACTIVATEDLIST, 0, 0, 0, ParseGetGPRSContextActivatedListInternal, NULL, (LPVOID)(iContext-1));
    //}

    //for (UINT i = 0; i < MAX_CONTEXTS; i++)
    //{	
   	//    RILRetailTrace((TEXT("RILDrv_EnterGPRSDataMode: After g_RILCGACT[%d]= %d\n"), i, g_RILCGACT[i]));        
   	//}

    // Send "ATD*99#" instead of "AT+CDATA" because the former is tested by OEM1 and acts in the same manner as far as we're concerned
    // Parameters to RILDrv_EnterGPRSDataMode() may be ignored or arguments can be supplied as part of the dial string instead
    strcpy(szCmd,"ATD*99**");
    szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
    TBD_ASSERT(NULL != szWalk);

    if (lpEnterGprsDataMode)
    {

        // Build command
        LPSTR szString;
        if (!StringFromFlag(lpEnterGprsDataMode->dwL2Protocol,g_GprsL2Protocols, NUM_GPRSL2PROTOCOLS,szString))
        {
            goto Error;
        }
        (void)_snprintfz(szWalk, MAX_ATCMD_LEN, "%s",szString);
        szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
        TBD_ASSERT(NULL != szWalk);

        /* Only work for one context */
        for (DWORD i=0;i<lpEnterGprsDataMode->dwNumContexts;i++)
		{
	        RILGPRSCONTEXT *pContext = NULL;
			DWORD dwTmpContext = lpEnterGprsDataMode->dwContextID[i];

	        pContext = (RILGPRSCONTEXT *)(g_RILGPRSContext + (sizeof(RILGPRSCONTEXT) * (dwTmpContext - 1)));
	        if (pContext->cbSize > 0)
        	{
	            (void)_snprintfz(szWalk, MAX_ATCMD_LEN - (szWalk - szCmd), "*%u", lpEnterGprsDataMode->dwContextID[i]);
	            szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
    		    TBD_ASSERT(NULL != szWalk);
        	}
		}
        
		(void)strncpyz(szWalk, "#\r", MAX_ATCMD_LEN - (szWalk -szCmd));
    }

#ifdef RIL_FAKECSQ
    g_fFakeSignalStrength = TRUE;
#endif

    // Workaround for bug in DSR handling in the MC55: when the GPRS data mode is entered while
    // the ring line of the data port is still on due to an incomming URC, the DSR line will be
    // set to low together with the ringe line. This would cause the command mode detection to
    // detect the command mode when actually the online mode is active.
    pPort = pHandle->GetDevice()->GetComDevice(iPort);
    if (pPort != NULL)
    {
        int iCount;
        DWORD dwMask;

        iCount = 0;
        while (pPort->VirtGetCommModemStatus(&dwMask)) {
            if ((dwMask & MS_RING_ON) == 0)
                break;
            Sleep(50);
            if (iCount++ > 100) // we wait at maximum 5s.
                break;
        }
    }

    if (!QueueCmd(iPort,
                  pHandle,
                  szCmd,
                  dwOptions,
                  APIID_ENTERGPRSDATAMODE,
                  pfnParse,  // Parse fn
                  NULL,     // Ptr to notification data
                  hr))
    {
        hr = E_FAIL;
        goto Error;
    }

    Error:
    return hr;
}
/*
+CGPADDR: <cid>,<PDP_addr>
[<CR><LF>+CGPADDR: <cid>,<PDP_addr>
[...]]
*/
HRESULT ParseGetGPRSAddress(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetGPRSAddress);

    UINT nValue;
    HRESULT hr = E_FAIL;
    LPCSTR szAddr, szAddrEnd;
    LPTSTR wszAddrReturned=NULL;
    DWORD dwStringLength=0;
    pBlob = NULL;
    cbBlob = 0;

    // Note: The pdp address is optional, so ignore it if it's not there and return an empty string
    // Also, ericsson doesn't even give us the cid, so ignore that if it's not present also

    if (  (!ParseRspPrefix(szRsp, szRsp))
       || (!MatchStringBeginning(szRsp, "+CGPADDR: ", szRsp))
       || (!ParseUInt(szRsp, TRUE, nValue, szRsp))
       || (!ParseRspParamSeparator(szRsp, szRsp)) )
    {
        // Rig szAddr so that if we don't find anything, we'll return an empty string
        szAddr=szAddrEnd="\r\n";
    }
    else
    {
        szAddr = szRsp;

        // Parse ,<pd1>[,...[,pdN]]
        szAddrEnd = strstr(szAddr, "\r\n");
        if (!szAddrEnd)
        {
            goto Error;
        }

        szRsp = szAddrEnd;
    }

    // Set dwParameterLength to be size of string in bytes counting null char at end
    dwStringLength = ((szAddrEnd-szAddr)+1);
    wszAddrReturned = (LPTSTR)AllocBlob(dwStringLength * sizeof(TCHAR));
    if (!wszAddrReturned)
    {
        goto Error;
    }

    (void)wcsncpyz(wszAddrReturned, WideString(szAddr,'\r'), dwStringLength);

    pBlob = (void*)wszAddrReturned;
    cbBlob = dwStringLength * sizeof(TCHAR);
    hr = S_OK;

    Error:
    if (FAILED(hr))
    {
        FreeBlob(wszAddrReturned);
    }

    return hr;
}

// +CGPADDR=<dwContextID>[,<dwContextID>...]
HRESULT RILDrv_GetGPRSAddress (DWORD dwParam, DWORD dwContextID)
{
    TBD_FUNCTION(RILDrv_GetGPRSAddress);

    HRESULT hr = E_INVALIDARG;
    COM_PORT_TYPE        iPort;

    iPort = g_ComManager.GetPortFromContextId(dwContextID);

    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    if (!pHandle || iPort == INVALID_PORT)
    {
        goto Error;
    }

    // Build command
    char szCmd[MAX_ATCMD_LEN];
    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CGPADDR=%u\r", dwContextID);

    if (!QueueCmd(iPort,
                  pHandle,
                  szCmd,
                  CMDOPT_NONE,
                  APIID_GETGPRSADDRESS,
                  ParseGetGPRSAddress,  // Parse fn
                  NULL,     // Ptr to notification data
                  hr))
    {
        hr = E_FAIL;
        goto Error;
    }

    Error:
    return hr;
}

// +CGANS=<params>
/*
typedef struct rilgprsanswer_tag
{
    DWORD cbSize;                       // @field structure size in bytes
    BOOL fAnswer;                       // @parm TRUE: accept, FALSE: reject
    DWORD dwL2Protocol;                 // @parm an optional RILL2PROTOCOL_* constant
    DWORD dwNumContexts;                // @parm number of contexts which follow
    DWORD dwContextID[];                // @parm identifies the context(s) to enter data state
} RILGPRSANSWER, *LPRILGPRSANSWER;
*/
HRESULT RILDrv_GPRSAnswer (DWORD dwParam, const RILGPRSANSWER *lpGprsAnswer)
{
    TBD_FUNCTION(RILDrv_GPRSAnswer);

    HRESULT hr = E_INVALIDARG;
    char szCmd[MAX_ATCMD_LEN];
    LPSTR szWalk = szCmd;
    DWORD i;
    COM_PORT_TYPE iPort;

    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    if (!pHandle)
    {
        goto Error;
    }

    if (lpGprsAnswer->dwNumContexts != 1)
    {
        RILRetailTrace((TEXT("RilDrv: Tried to open %u contexts at the same time.\r\n"), lpGprsAnswer->dwNumContexts));
        hr = E_INVALIDARG;
        goto Error;
    }

    iPort = g_ComManager.GetPortFromContextId(lpGprsAnswer->dwContextID[0]);
    if (iPort == INVALID_PORT)
    {
        goto Error;
    }

    // Build command

    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CGANS=%u,", lpGprsAnswer->fAnswer ? 1 : 0);
    szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
    TBD_ASSERT(NULL != szWalk);

    LPSTR szString;
    if (!StringFromFlag(lpGprsAnswer->dwL2Protocol,g_GprsL2Protocols, NUM_GPRSL2PROTOCOLS,szString))
    {
        goto Error;
    }
    (void)_snprintfz(szWalk, MAX_ATCMD_LEN, "\"%s\"", szString);
    szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
    TBD_ASSERT(NULL != szWalk);

    for (i=0;i<lpGprsAnswer->dwNumContexts;i++)
    {
        (void)_snprintfz(szWalk, MAX_ATCMD_LEN - (szWalk - szCmd), ",%u", lpGprsAnswer->dwContextID[i]);
        szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
        TBD_ASSERT(NULL != szWalk);
    }

    // Add "\r"
    (void)strncpyz(szWalk, "\r", MAX_ATCMD_LEN - (szWalk - szCmd));

    if (!QueueCmd(iPort,
                  pHandle,
                  szCmd,
                  CMDOPT_NONE,
                  APIID_GPRSANSWER,
                  NULL,  // Parse fn
                  NULL,     // Ptr to notification data
                  hr))
    {
        hr = E_FAIL;
        goto Error;
    }

    Error:
    return hr;
}

static HRESULT ParseGetSMONGGPRSRegistrationStatus(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetGPRSRegistrationStatus);
    UINT nValue;
    HRESULT hr = E_FAIL;
    DWORD *pdwRegStatus=NULL;
    LPCSTR szDummy;

    pBlob = NULL;
    cbBlob = 0;

    pdwRegStatus = (DWORD*)AllocBlob(sizeof(DWORD));
    if (!pdwRegStatus)
    {
        goto Error;
    }

    // Parse "<prefix>"
    if (!ParseRspPrefix(szRsp, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    if (!MatchStringAnywhere(szRsp, "\r\n", szRsp))
    {
        hr = E_FAIL;
        goto Error;
    }
    if (!MatchStringBeginning(szRsp, "BCCH", szDummy))
    {
        if (!MatchStringAnywhere(szRsp, "\r\n", szRsp))
        {
            hr = E_FAIL;
            goto Error;
        }
    }
    if (!MatchStringAnywhere(szRsp, "\r\n", szRsp))
    {
        hr = E_FAIL;
        goto Error;
    }

    nValue = (UINT)atoi(szRsp + 6);

    // Find "<postfix>"
    if (!FindRspPostfix(szRsp, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    if (nValue == 0)
        *pdwRegStatus = RIL_REGSTAT_UNREGISTERED;
    else
        *pdwRegStatus = g_dwGPRSRegStatus;
        

    pBlob = (void*)pdwRegStatus;
    cbBlob = sizeof(DWORD);
    hr = S_OK;

Error:
    return hr;
}


HRESULT ParseGetGPRSRegistrationStatus(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetGPRSRegistrationStatus);
    HRESULT hr = E_FAIL;
    DWORD *pdwRegStatus=NULL;
    pBlob = NULL;
    cbBlob = 0;

    pdwRegStatus = (DWORD*)AllocBlob(sizeof(DWORD));
    if (!pdwRegStatus)
    {
        goto Error;
    }

    *pdwRegStatus = g_dwGPRSRegStatus;

    pBlob = (void*)pdwRegStatus;
    cbBlob = sizeof(DWORD);
    hr = S_OK;

    Error:
    if (FAILED(hr))
    {
        FreeBlob(pdwRegStatus);
    }

    return hr;
}

// +CGREG?
HRESULT RILDrv_GetGPRSRegistrationStatus (DWORD dwParam)
{
    TBD_FUNCTION(RILDrv_GetGPRSRegistrationStatus);

    HRESULT hr = E_INVALIDARG;
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    if (!pHandle)
    {
        goto Error;
    }

    if (g_dwGPRSRegStatus == RIL_REGSTAT_HOME || g_dwGPRSRegStatus == RIL_REGSTAT_ROAMING)
    {
        // The module reports, that we are attached to GPRS, but the current cell might not
        // have GPRS, so we have to check with AT^SMONG if the cell really supports GPRS.
        if (!QueueCmd(COMMAND_PORT, pHandle, "AT^SMONG=1\r", CMDOPT_NONE, APIID_GETGPRSREGISTRATIONSTATUS, ParseGetSMONGGPRSRegistrationStatus,  NULL, hr))
        {
            hr = E_FAIL;
            goto Error;
        }
    }
    else
    {
        if (!QueueCmd(COMMAND_PORT, pHandle, NULL, CMDOPT_NOOP, APIID_GETGPRSREGISTRATIONSTATUS, ParseGetGPRSRegistrationStatus,  NULL, hr))
        {
            hr = E_FAIL;
            goto Error;
        }
    }

    Error:
    return hr;
}

// +CGCLASS: <class>
HRESULT ParseGetGPRSClass(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetGprsCapsClass);

    HRESULT hr = ParseFakeDWord(RIL_GPRSCLASS_GSMORGPRS, pBlob, cbBlob);

    return hr;
}

// +CGCLASS?
HRESULT RILDrv_GetGPRSClass (DWORD dwParam)
{
    TBD_FUNCTION(RILDrv_GetGPRSClass);

    HRESULT hr = E_INVALIDARG;
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);

    if (!pHandle)
    {
        goto Error;
    }

    if (!QueueCmd(COMMAND_PORT,
                  pHandle,
                  NULL,
                  CMDOPT_NOOP,
                  APIID_GETGPRSCLASS,
                  ParseGetGPRSClass,  // Parse fn
                  NULL,     // Ptr to notification data
                  hr))
    {
        hr = E_FAIL;
        goto Error;
    }

    Error:
    return hr;
}

// +CGCLASS=[A|B|C|CG|CC]
HRESULT RILDrv_SetGPRSClass (DWORD dwParam, DWORD dwClass)
{
    TBD_FUNCTION(RILDrv_SetGPRSClass);
    HRESULT hr = E_INVALIDARG;
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);

    if (!pHandle)
    {
        goto Error;
    }

    // Siemens modules are always in class B
    if (dwClass != RIL_GPRSCLASS_GSMORGPRS)
        return E_INVALIDARG;

    if (!QueueCmd(COMMAND_PORT,
                  pHandle,
                  NULL,
                  CMDOPT_NOOP,
                  APIID_GETGPRSCLASS,
                  ParseGetGPRSClass,  // Parse fn
                  NULL,     // Ptr to notification data
                  hr))
    {
        hr = E_FAIL;
        goto Error;
    }

    Error:
    return hr;
}

/*
+CGSMS: <service>
<service>: a numeric parameter which indicates the service or service preference to be used
0 GPRS
1 circuit switched
2 GPRS preferred (use circuit switched if GPRS not available)
3 circuit switched preferred (use GPRS if circuit switched not available)
*/
HRESULT ParseGetMOSMSService(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetMOSMSService);
    UINT nValue;
    HRESULT hr = E_FAIL;
    DWORD *pdwMoSmsService=NULL;
    pBlob = NULL;
    cbBlob = 0;

    // Parse "<prefix>"
    if (!ParseRspPrefix(szRsp, szRsp))
    {
        goto Error;
    }

    // Parse "+CGSMS: "
    if (!MatchStringBeginning(szRsp, "+CGSMS: ", szRsp))
    {
        goto Error;
    }

    // Parse <service>
    if (!ParseUInt(szRsp, TRUE, nValue, szRsp))
    {
        goto Error;
    }

    pdwMoSmsService = (DWORD*)AllocBlob(sizeof(DWORD));
    if (!pdwMoSmsService)
    {
        goto Error;
    }

    FlagFromValue(nValue,g_GprsMOSMSService,NUM_GPRSMOSMSSERVICE,*pdwMoSmsService);

    pBlob = (void*)pdwMoSmsService;
    cbBlob = sizeof(DWORD);
    hr = S_OK;

    Error:
    if (FAILED(hr))
    {
        FreeBlob(pdwMoSmsService);
    }

    return hr;
}

// +CGSMS?
HRESULT RILDrv_GetMOSMSService (DWORD dwParam)
{
    TBD_FUNCTION(RILDrv_GetMOSMSService);

    HRESULT hr = E_INVALIDARG;
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    if (!pHandle)
    {
        goto Error;
    }

    if (!QueueCmd(COMMAND_PORT,
                  pHandle,
                  "AT+CGSMS?\r",
                  CMDOPT_NONE,
                  APIID_GETMOSMSSERVICE,
                  ParseGetMOSMSService,  // Parse fn
                  NULL,     // Ptr to notification data
                  hr))
    {
        hr = E_FAIL;
        goto Error;
    }

    Error:
    return hr;
}

// +CGSMS=[0|1|2|3]
HRESULT RILDrv_SetMOSMSService (DWORD dwParam, DWORD dwMoSmsService)
{
    TBD_FUNCTION(RILDrv_SetMOSMSService);

    UINT Value;
    HRESULT hr = E_INVALIDARG;
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    if (!pHandle)
    {
        goto Error;
    }

    // Build command
    char szCmd[MAX_ATCMD_LEN];
    if (!ValueFromFlag(dwMoSmsService,g_GprsMOSMSService,NUM_GPRSMOSMSSERVICE,Value))
    {
        goto Error;
    }
    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CGSMS=%u\r",Value);


    if (!QueueCmd(COMMAND_PORT,
                  pHandle,
                  szCmd,
                  CMDOPT_NONE,
                  APIID_SETMOSMSSERVICE,
                  NULL,  // Parse fn
                  NULL,  // Ptr to notification data
                  hr))
    {
        hr = E_FAIL;
        goto Error;
    }

    Error:
    return hr;
}

// +CGCLASS: (list of supported <class>s)
HRESULT ParseGetGprsCapsClass(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetGprsCapsClass);

    HRESULT hr = ParseFakeDWord(RIL_GPRSCLASS_GSMORGPRS, pBlob, cbBlob);

    return hr;
}

// +CGDCONT: (range of supported <cid>s),<PDP_type>,,,(list of supported <d_comp>s),(list of supported <h_comp>s)[,(list of supported <pd1>s)[,...[,(list of supported <pdN>s)]]]
// [<CR><LF>+CGDCONT: (range of supported <cid>s),<PDP_type>,,,(list of supported <d_comp>s),(list of supported <h_comp>s)[,(list of supported <pd1>s)[,...[,(list of supported <pdN>s)]]]
// [...]]
HRESULT ParseGetGprsCapsContext(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetGprsCapsContext);
    RILGPRSCONTEXTCAPS GPRSContextCaps;
    HRESULT hr = E_FAIL;

    pBlob = NULL;
    cbBlob = 0;

    memset(&GPRSContextCaps, 0x00, sizeof(GPRSContextCaps));

    // Also all Siemens modules allow two GPRS contexts, we can only use with the MC75 two at the
    // same time. So the RIL have to report back, that there ist only only one context available
    // for all modules expect the MC75.
    GPRSContextCaps.ContextIDRange.dwMinValue = 1;
    if (IS_ADI)
        GPRSContextCaps.ContextIDRange.dwMaxValue = 2;
    else
        GPRSContextCaps.ContextIDRange.dwMaxValue = 1;

    GPRSContextCaps.dwParams|= RIL_PARAM_GCONT_CONTEXTID;

    GPRSContextCaps.dwProtocolType = RIL_GPRSPROTOCOL_IP;
    GPRSContextCaps.dwParams|= RIL_PARAM_GCONT_PROTOCOLTYPE;

    GPRSContextCaps.dwDataCompression = RIL_GPRSDATACOMP_OFF;
    GPRSContextCaps.dwParams|= RIL_PARAM_GCONT_DATACOMPRESSION;

    GPRSContextCaps.dwHeaderCompression = RIL_GPRSHEADERCOMP_ON;
    GPRSContextCaps.dwParams|= RIL_PARAM_GCONT_HEADERCOMPRESSION;

    // Init size of GPRSContextCaps
    GPRSContextCaps.cbSize = sizeof(GPRSContextCaps);

    pBlob = (void*)&GPRSContextCaps;
    cbBlob = GPRSContextCaps.cbSize;
    hr = S_OK;

    return hr;
}

// +XXXXXX: <PDP_type>, (list of supported <precedence>s), (list of supported <delay>s), (list of supported <reliability>s) , (list of supported <peak>s), (list of supported <mean>s)
// [<CR><LF>+XXXXXX: <PDP_type>, (list of supported <precedence>s), (list of supported <delay>s), (list of supported <reliability>s) , (list of supported <peak>s), (list of supported <mean>s)
// [...]]
HRESULT ParseQOSCapsList(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPCSTR szCmd)
{
    TBD_FUNCTION(ParseQOSCapsList);
    PBYTE pBuffer=NULL;
    DWORD dwBufferSize=0;

    RILGPRSQOSPROFILECAPS *pQOSProfileCaps;

    char szValue[MAX_ATCMD_LEN];

    HRESULT hr = E_FAIL;
    BOOL bSuccess;

    pBlob = NULL;
    cbBlob = 0;

    // Parse "<prefix>"
    if (!ParseRspPrefix(szRsp, szRsp))
    {
        hr = E_FAIL;
        goto Error;
    }

    // Parse "+XXXXXX: "
    while (MatchStringBeginning(szRsp, szCmd, szRsp))
    {
        // Reallocate our buffer for the additional data
        pBuffer = (PBYTE)ReallocBlob(pBuffer,dwBufferSize+sizeof(RILGPRSQOSPROFILECAPS));
        if (!pBuffer)
        {
            goto Error;
        }

        pQOSProfileCaps = (RILGPRSQOSPROFILECAPS *)(pBuffer+dwBufferSize);
        memset(pQOSProfileCaps, 0x00, sizeof(RILGPRSQOSPROFILECAPS));
        pQOSProfileCaps->cbSize=sizeof(RILGPRSQOSPROFILECAPS);

        dwBufferSize+=sizeof(RILGPRSQOSPROFILECAPS);

        // Parse <PDP_type>
        if (!ParseString(szRsp, szValue, MAX_ATCMD_LEN, szRsp))
        {
            goto Continue;
        }

        FlagFromString(szValue, g_GprsPDPTypes, NUM_GPRSPDPTYPES,pQOSProfileCaps->dwProtocolType);

        // Parse ,(list of supported <precedence>s)
        if (!ParseRspParamSeparator(szRsp, szRsp) ||
           (!ParseRangeList(szRsp, g_GprsPrecedenceClass, NUM_GPRSPRECEDENCECLASS, pQOSProfileCaps->dwPrecedenceClass, szRsp)) )
        {
           goto Continue;
        }
        pQOSProfileCaps->dwParams|= RIL_PARAM_GQOSP_PRECEDENCECLASS;

        // ,(list of supported <delay>s)
        if (!ParseRspParamSeparator(szRsp, szRsp) ||
           (!ParseRangeList(szRsp, g_GprsDelayClass,NUM_GPRSDELAYCLASS, pQOSProfileCaps->dwDelayClass, szRsp)) )
        {
            goto Continue;
        }
        pQOSProfileCaps->dwParams|= RIL_PARAM_GQOSP_DELAYCLASS;

        // Parse ,(list of supported <reliability>s)
        if (!ParseRspParamSeparator(szRsp, szRsp) ||
           (!ParseRangeList(szRsp, g_GprsReliabilityClass,NUM_GPRSRELIABILITYCLASS, pQOSProfileCaps->dwReliabilityClass, szRsp)) )
        {
            goto Continue;
        }
        pQOSProfileCaps->dwParams|= RIL_PARAM_GQOSP_RELIABILITYCLASS;

        // Parse ,(list of supported <peak>s)
        if (!ParseRspParamSeparator(szRsp, szRsp) ||
           (!ParseRangeList(szRsp, g_GprsPeakThruClass,NUM_GPRSPEAKTHRUCLASS, pQOSProfileCaps->dwPeakThruClass, szRsp)) )
        {
            goto Continue;
        }

        // Parse ,(list of supported <mean>s)
        if (!ParseRspParamSeparator(szRsp, szRsp) ||
           (!ParseRangeList(szRsp, g_GprsMeanThruClass,NUM_GPRSMEANTHRUCLASS, pQOSProfileCaps->dwMeanThruClass, szRsp)) )
        {
            goto Continue;
        }
        pQOSProfileCaps->dwParams|= RIL_PARAM_GQOSP_MEANTHRUCLASS;

        Continue:
        // Find "<postfix>"
        bSuccess = FindRspPostfix(szRsp, szRsp);
        if (!bSuccess)
        {
            goto Error;
        }
    }

    pBlob = (void*)pBuffer;
    cbBlob = dwBufferSize;
    hr = S_OK;

    Error:
    if (FAILED(hr))
    {
        FreeBlob(pBuffer);
    }
    return hr;
}

// +CGQREQ: <PDP_type>, (list of supported <precedence>s), (list of supported <delay>s), (list of supported <reliability>s) , (list of supported <peak>s), (list of supported <mean>s)
// [<CR><LF>+CGQREQ: <PDP_type>, (list of supported <precedence>s), (list of supported <delay>s), (list of supported <reliability>s) , (list of supported <peak>s), (list of supported <mean>s)
// [...]]
HRESULT ParseGetGprsCapsQOS(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetGprsCapsQOS);
    return ParseQOSCapsList(szRsp,pBlob,cbBlob,"+CGQREQ: ");
}

// +CGQMIN: <PDP_type>, (list of supported <precedence>s), (list of supported <delay>s), (list of supported <reliability>s) , (list of supported <peak>s), (list of supported <mean>s)
// [<CR><LF>+CGQMIN: <PDP_type>, (list of supported <precedence>s), (list of supported <delay>s), (list of supported <reliability>s) , (list of supported <peak>s), (list of supported <mean>s)
// [...]]
HRESULT ParseGetGprsCapsQOSMin(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetGprsCapsQOS);
    return ParseQOSCapsList(szRsp,pBlob,cbBlob,"+CGQMIN: ");
}

// +CGSMS: (list of currently available <service>s)
HRESULT ParseGetGprsCapsSMOSMS(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetGprsCapsSMOSMS);
    HRESULT hr = E_FAIL;
    DWORD *pdwMoSmsService=NULL;
    pBlob = NULL;
    cbBlob = 0;

    // Parse "<prefix>"
    if (!ParseRspPrefix(szRsp, szRsp))
    {
        goto Error;
    }

    // Parse "+CGDCONT: "
    if (!MatchStringBeginning(szRsp, "+CGSMS: ", szRsp))
    {
        goto Error;
    }

    pdwMoSmsService = (DWORD*)AllocBlob(sizeof(DWORD));
    if (!pdwMoSmsService)
    {
        goto Error;
    }

    // Parse (list of currently available <service>s)
    if (!ParseRangeList(szRsp, g_GprsMOSMSService,NUM_GPRSMOSMSSERVICE, *pdwMoSmsService, szRsp))
    {
        goto Error;
    }

    pBlob = (void*)pdwMoSmsService;
    cbBlob = sizeof(DWORD);
    hr = S_OK;

    Error:
    if (FAILED(hr))
    {
        FreeBlob(pdwMoSmsService);
    }

    return hr;
}

